import aiofiles
import os
import time
from datetime import datetime, timedelta
from typing import Annotated, Literal, Union
from uuid import UUID

import uvicorn
from fastapi import FastAPI, Path, Query, Body, Cookie, Header, status, Form, File, UploadFile, HTTPException, Request, \
    Depends
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from fastapi.openapi.docs import get_swagger_ui_html, get_swagger_ui_oauth2_redirect_html, get_redoc_html
from fastapi.responses import HTMLResponse,JSONResponse,PlainTextResponse
from starlette.staticfiles import StaticFiles
from pydantic import BaseModel, Field, HttpUrl, EmailStr


async def verify_token(x_token: str |  None = Header(None),request: Request = None):
    if request and request.url.path in ["/docs","/redoc",]:
        return
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,detail="X-Token header invalid")

async def verify_key(x_key: str | None = Header(None),request: Request = None):
    if request and request.url.path in ["/docs","/redoc"]:
        return
    if x_key != "fake-super-secret-key":
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,detail="X-Key header invalid")
    return x_key


# 创建FastAPI实例，禁用掉FastAPI会自动生成Swagger UI和Redoc文档
app = FastAPI(docs_url=None, redoc_url=None,
              dependencies=[Depends(verify_token),Depends(verify_key)],)

# 静态文件挂载（路由与静态文件映射）
app.mount("/static", StaticFiles(directory="../statics"), name="static")


# 重新提供一个Swagger UI，相当于我们自己重写了这么一个路由
@app.get("/docs", include_in_schema=False)
def custom_swagger_ui():
    return get_swagger_ui_html(
        openapi_url = "/openapi.json",
        title = "Swagger UI for FastAPI",
        swagger_js_url="/static/swagger-ui-bundle.min.js",
        swagger_css_url="/static/swagger-ui.min.css"
    )

# 这里与Swagger UI一样，重新提供Redoc
@app.get("/redoc", include_in_schema=False)
def custom_redoc():
    return get_redoc_html(
        openapi_url = "/openapi.json",
        title = "Redoc for FastAPI",
        redoc_js_url="/static/redoc.standalone.js"
    )

# 依赖项函数
async def common_parameters(
        q: str | None = None,
        page_index: int = 1,
        page_size: int = 10,
):
    return {
        "q": q,
        "page_index": page_index,
        "page_size": page_size
    }

items_db = [{"item_name": "手机"}, {"items_name":"日化"},{"items_name": "笔记本"},
            {"item_name": "电脑"}, {"items_name": "网络设备"},{"items_name": "智能音箱"},
            {"item_name": "平板"}]


class CommonQueryParams:
    def __init__(self,q: str| None = None,page_index: int = 1,page_size: int = 10):
        self.q = q
        self.page_index = page_index
        self.page_size = page_size


@app.get("/items")
# async def get_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
async def get_items(commons: CommonQueryParams = Depends()):
    result = {}
    if commons.q:
        result.update({"q": commons.q})
    start_index = (commons.page_index-1)*commons.page_size
    end_index = start_index + commons.page_size
    items = items_db[start_index:end_index]
    result.update({"items": items})
    return result

@app.get("/users")
async def get_users(commons: CommonQueryParams = Depends(CommonQueryParams)):
    return commons


async def query_extractor(q: str | None = None):
    return q

async def query_or_cookie_extractor(
        q: str = Depends(query_extractor),
        last_query: str | None = Cookie(default=None)
):
    if not q:
        return last_query
    return q

@app.get("/users")
async def get_users(query_or_default: str = Depends(query_or_cookie_extractor)):
    return {"q_or_cookie": query_or_default}




# @app.get("/items/check", dependencies=[Depends(verify_token),Depends(verify_key)])
@app.get("/items/check")
async def check_items():
    return {"message": "Successful check"}



class DBSession:
    def __init__(self):
        print("init db session")

    def close(self):
        print("close db session")

async def get_db_session():
    db_session = DBSession()
    try:
        yield db_session
    finally:
        db_session.close()

@app.get("/orders")
async def get_orders(db_session: DBSession = Depends(get_db_session)):
    print("db_session:", db_session)
    return {"message": "Successful get orders"}


class OwnerError(Exception):
    pass

async def get_order_no():
    try:
        yield "SO123456"
    except OwnerError as e:
        raise HTTPException(status_code=400, detail=f"Owner error： {e}")

@app.get("/order/{order_id}")
async def get_order(order_id: int, order_no: str = Depends(get_order_no)):
    if order_id == 1:
        raise HTTPException(status_code=400, detail="Order not found")
    if order_no == "SO123456":
        raise OwnerError("订单号重复")

if __name__ == '__main__':
    app.debug = True
    uvicorn.run("main:app", host="127.0.0.1", port=8025, reload=True)

